/*
 * XMLElement.cpp
 *
 * Modela un tag, el mismo puede tener mas tags adentro, modelado por los child.
 */

#include "XMLElement.h"
#include "NoSuchXmlElementException.h"

using namespace std;

XMLElement::XMLElement(string name) {
	this->name = name;
}
XMLElement::~XMLElement() {
}

string * XMLElement::getName(void) {
	return & name;
}

void XMLElement::setName(string name) {
	this->name = name;
}

string * XMLElement::getValue(void) {
	return & value;
}

void XMLElement::setValue(string value) {
	this->value = value;
}

list<XmlAttribute> & XMLElement::getAttributes(void) {
	return attributes;
}

void XMLElement::setAttributes(list<XmlAttribute> & attributes) {
	this->attributes = attributes;
}

list<XMLElement> & XMLElement::getChildren(void) {
	return children;
}

void XMLElement::setChildren(list<XMLElement> & children) {
	this->children = children;
}

int XMLElement::getLine(void) {
	return line;
}
void XMLElement::setLine(int line) {
	this->line = line;
}
int XMLElement::getColumn(void) {
	return column;
}
void XMLElement::setColumn(int column) {
	this->column = column;
}
int XMLElement::getLevel(void) {
	return level;
}
void XMLElement::setLevel(int level) {
	this->level = level;
}

list<XMLElement*> XMLElement::getElementsByName(string name){

	list<XMLElement>::iterator childrenIterator;
	list<XMLElement*>::iterator subIterator;
	list<XMLElement*> queryResult;
	list<XMLElement*> childrenList;

	if(this->name.compare(name)==0) {
		queryResult.push_front(this);
	}
	if(this->getChildren().size() > 0) {
		for (childrenIterator = getChildren().begin(); childrenIterator != getChildren().end(); ++childrenIterator) {
			try {
				childrenList = childrenIterator->getElementsByName(name);
				for(subIterator = childrenList.begin(); subIterator != childrenList.end(); ++subIterator) {
					queryResult.push_front(*subIterator);
				}
			} catch (NoSuchXmlElementException e) {
				// Ignora la NO existencia de nodos en sus hijos.
			}
		}
	}
	if(queryResult.size() == 0) {
		string message = "No se encontraron elementos con nombre ";
		message.append(name);
		throw NoSuchXmlElementException(message);
	}
	return queryResult;
}

XMLElement * XMLElement::getElementById(string idValue){
	
	list<XMLElement>::iterator childrenIterator;
	list<XMLElement*>::iterator subIterator;
	XMLElement *ptrElement = 0;

	try {
		XmlAttribute *id = getAttributeByName("id");
		if(id->getValue()->compare(idValue) == 0) {
			return this;
		}
	}catch(NoSuchXmlElementException e) {
		// Ignora elementos sin Ids.
	}
	if(this->getChildren().size() > 0) {
		for (childrenIterator = getChildren().begin(); childrenIterator != getChildren().end(); ++childrenIterator) {
			try {
				return  childrenIterator->getElementById(idValue); // Retorna el primero que encuentra, porque el id no se repite.
			}catch(NoSuchXmlElementException e) {
				// Ignora elementos sin Ids.
			}
		}
	}
	throw NoSuchXmlElementException("No existe un elemento con ese id."); // Si el id no es identificado por el objeto, o los hijos, arroja la exepcion.
}

XmlAttribute * XMLElement::getAttributeByName(string name){

	XmlAttribute * p = new XmlAttribute("");
	list<XmlAttribute>::iterator attributesIterator;
	for (attributesIterator = getAttributes().begin(); attributesIterator != getAttributes().end(); ++attributesIterator) {
		XmlAttribute atr = *attributesIterator;
		if(atr.getName()->compare(name) == 0) {
			*p = atr;
			return p;
		}
	}
	throw NoSuchXmlElementException("No se encontro el atributo: "+name);
}

string & XMLElement::toString(void) {
	
	string *PStringValue = new string("\n");
	string &toStringValue = * PStringValue;
	toStringValue.append(getLevel(), '\t');
	toStringValue.append(string("XMLElement:"));
	char bufferLine[5], bufferColumn[5];
	_itoa_s(getLine(), bufferLine, 10);
	_itoa_s(getColumn(), bufferColumn, 10);
	toStringValue.append(string(" name:"));
	toStringValue.append(getName()->c_str());
	toStringValue.append(string(" ,Value:"));
	toStringValue.append(getValue()->c_str());
	toStringValue.append(string(" ,Line:"));
	toStringValue.append(bufferLine);
	toStringValue.append(string(" ,Column:"));
	toStringValue.append(bufferColumn);
	toStringValue.append(1, '\n');
	toStringValue.append(getLevel(), '\t');
	toStringValue.append(string("   Attributes:"));
	list<XmlAttribute>::iterator attributesIterator;
	for (attributesIterator = getAttributes().begin(); attributesIterator != getAttributes().end(); ++attributesIterator) {
		toStringValue.append(1, '\n');
		toStringValue.append(getLevel() + 1, '\t');
		toStringValue.append((*attributesIterator).toString());
	}
	toStringValue.append(1, '\n');
	toStringValue.append(getLevel(), '\t');
	toStringValue.append(string("   Childs:"));
	list<XMLElement>::iterator ChildrenIterator;
	for (ChildrenIterator = getChildren().begin(); ChildrenIterator != getChildren().end(); ++ChildrenIterator) {
		toStringValue.append((*ChildrenIterator).toString());
	}
	toStringValue.append(1, '\n');
	return toStringValue;
}
